package com.stripe.android.stripe3ds2.transaction

import com.google.common.truth.Truth.assertThat
import com.nimbusds.jose.JWSHeader
import com.nimbusds.jose.JWSObject
import com.nimbusds.jose.jwk.JWK
import com.nimbusds.jose.util.Base64
import com.nimbusds.jose.util.X509CertUtils
import com.stripe.android.stripe3ds2.observability.ErrorReporter
import com.stripe.android.stripe3ds2.observability.FakeErrorReporter
import org.junit.runner.RunWith
import org.mockito.kotlin.argWhere
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.robolectric.RobolectricTestRunner
import java.security.cert.X509Certificate
import java.text.ParseException
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertFailsWith

@RunWith(RobolectricTestRunner::class)
@Suppress("ktlint:standard:max-line-length")
class JwsValidatorTest {

    private val errorReporter = mock<ErrorReporter>()

    @Test
    fun getPayload_withP256JWS_shouldReturnValidPayload() {
        val jwsValidator = create(false, emptyList())
        val payload = jwsValidator.getPayload(JWS_P256)

        assertThat(
            payload.getString("acsURL")
        ).isEqualTo(
            "https://simulator-3ds.selftestplatform.com/v2.1.0/acs/946/"
        )
        assertThat(payload.getString("acsEphemPubKey"))
            .isNotNull()
        assertThat(payload.getString("sdkEphemPubKey"))
            .isNotNull()
    }

    @Test
    fun getPayload_withES256JWS_shouldReturnValidPayload() {
        val jwsValidator = create(false, emptyList())
        val payload = jwsValidator.getPayload(JWS_ES256)
        assertThat(
            payload.getString("acsURL")
        ).isEqualTo(
            "https://simulator-3ds.selftestplatform.com/v2.1.0/acs/946/"
        )
        assertThat(payload.getString("acsEphemPubKey"))
            .isNotNull()
        assertThat(payload.getString("sdkEphemPubKey"))
            .isNotNull()
    }

    @Test
    fun getPayload_withInvalidJws_shouldThrowException() {
        val jwsValidator = create(true, emptyList())
        assertFailsWith<ParseException> {
            jwsValidator.getPayload("invalid")
        }
    }

    @Test
    fun getPayload_withValidJwsInLiveModeWithoutRootCerts_shouldThrowException() {
        val jwsValidator = create(true, emptyList())
        assertFailsWith<IllegalStateException> {
            jwsValidator.getPayload(JWS_P256)
        }
    }

    @Test
    fun getPayload_whenInTestMode_doesNotValidate() {
        val jwsValidator = create(false, emptyList())
        val payload = jwsValidator.getPayload(UNSIGNED_JWS)

        assertThat(
            payload.getString("acsURL")
        ).isEqualTo(
            "https://hooks.stripe.com/3d_secure_2_test/app_challenge/hBmDz2QRY3UNPPSSyAdMMt1IsXecwc8U6TerBb4B_co="
        )
        assertThat(payload.getString("acsEphemPubKey"))
            .isNotNull()
        assertThat(payload.getString("sdkEphemPubKey"))
            .isNotNull()
    }

    @Ignore("Ignore tests with expired certificates")
    @Test
    fun isCertificateChainValid_withRealMastercardCerts_shouldReturnTrue() {
        val jwsValidator = create(true, emptyList())

        val encodedAcsCerts = listOf(
            Base64(
                "MIIFwjCCA6qgAwIBAgIQfrtGFUDBqtCgq+MYCT0IbzANBgkqhkiG9w0BAQsFADB4MQswCQYDVQQGEwJVUzETMBEGA1UEChMKTWFzdGVyQ2FyZDEoMCYGA1UECxMfTWFzdGVyQ2FyZCBJZGVudGl0eSBDaGVjayBHZW4gMzEqMCgGA1UEAxMhUFJEIE1hc3RlckNhcmQgM0RTMiBJc3N1ZXIgU3ViIENBMB4XDTE4MDgxMzA4Mjg1OFoXDTIwMDgxMjA4MDgxNlowgakxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQHEwtTYW50YSBDbGFyYTEaMBgGA1UEChMRQXJjb3QgU3lzdGVtcyBMTEMxMDAuBgNVBAsTJ0FDU01TLUFDUy1WMjEwLUNBX1RFQ0hOT0xPR0lFUy0yMjQyMS1DQTEhMB8GA1UEAxMYc2VjdXJlNXNpZ25pbmcuYXJjb3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuq3Z99XrW8QfcNXwPadKI21ncDKX5E5bKCC50ajtnOox4fXwIlmqxAAodcb+u5+Bqq/Kh1C09YLjDvoZnVuGPZzszFK9S8b9Ebzcothg62d/DoVNQA4D4QbCPxr9RY6Tht8B+TIUVRoy5fB3CjJfI3ojVngrClcs93YepkmLhwUIpgMrGaEb/PuNpy/U7orRKcGIRF68CBtySqYLK3S6IGI2BIVPBjGEyG2dwC51Z7F03cOfEA167DCDKpJ4oJLMH2IIcK+E879MPjCDqRxoOnmwss40MSeCYXLeI9F0ZwdwJ2r+M7DZzYOhJv9abkVxXTcK/E+kZx6zncyx3BwH3wIDAQABo4IBFDCCARAwDgYDVR0PAQH/BAQDAgeAMAkGA1UdEwQCMAAwHwYDVR0jBBgwFoAUT/fDn2LKVlRL30h0y3AcbzzdEEUwSAYIKwYBBQUHAQEEPDA6MDgGCCsGAQUFBzABhixodHRwOi8vb2NzcC5wa2kuaWRlbnRpdHljaGVjay5tYXN0ZXJjYXJkLmNvbTBpBgNVHR8EYjBgMF6gXKBahlhodHRwOi8vY3JsLnBraS5pZGVudGl0eWNoZWNrLm1hc3RlcmNhcmQuY29tLzRmZjdjMzlmNjJjYTU2NTQ0YmRmNDg3NGNiNzAxYzZmM2NkZDEwNDUuY3JsMB0GA1UdDgQWBBQ9nNELVzs+phBHKwb+pfzrFac9PzANBgkqhkiG9w0BAQsFAAOCAgEAEcy0P2qeO8nxf1RpO2QoursGVoo980q8OJz61pQ8zBR++PqSSzvB6qhyyCRAJYsVy8WDS9vdQsNoLt6D3osFH+PJtuQPR3vIc4TEj/HvpbKVcuXuKNC6grMhGUA94DF1CFMT+k3nuc5WvMrCOSB2yxEfoh/r28jGGl4Zn6z6S0foVgdxqfJ223Zj8Q40Iwk+2TjTSqXElBPA2oN5oCYBm+lex4fcpob5PinqZ2H5RSmFx/xKZrswiALiSnzS9C7D0UPCHTUzYolWf7+vvJHZADFNUg1v/WeNPfECQOZAmHKaPbPD+aqIZIe7AUiNBbUxH+1s95RkkX2dJ5kd9dnYlE1kjDwR/0WrH//XthVf9WELyB9MsravO3rP7YikyF7os5il+D86EibspGtGR+b1xES7PY6sJhBo0BREwugl3oK7DIBiBGS8BnIr3JLojy3y5BAgCqTXk2/PWJFc7x3YhYzMT6i2FqtIh8qkhiKguzMt9RuPrBoj0Ng0tqmD3iBlWFpabNq1il+ZFcZ2oVnJ8XE6ZeQYaJaL9XMRTq9bRqRZqUDAohikQGi6BD9bmslRiri5EtGryqy0hhXnwuPGslTsNno4O4u7dy6Y0Ym8e4eUTmnNtgx5kbSPmn9O6fQ4a0KIap+A2dtBmupTcFt92lW2EOhsI37X2rPIwJeOPFU="
            ),
            Base64(
                "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"
            ),
            MASTERCARD_ROOT_CERT_CONTENTS
        )

        assertThat(
            jwsValidator.isCertificateChainValid(encodedAcsCerts, MASTERCARD_ROOT_CERTS)
        ).isTrue()
    }

    @Test
    fun isCertificateChainValid_withSampleCerts_shouldReturnTrue() {
        val encodedRootCert = Base64(
            "MIIDXTCCAkWgAwIBAgIQbS4C4BSig7uuJ5uDpeT4VjANBgkqhkiG9w0BAQsFADBHMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEXMBUGA1UEAwwOUlNBIEV4YW1wbGUgRFMwHhcNMTcxMTIxMTE0ODQ5WhcNMjcxMjMxMTQwMDAwWjBHMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEXMBUGA1UEAwwOUlNBIEV4YW1wbGUgRFMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfgQ+0A4Jz0CWR5Ac/MdK2ABuCzttNkvBQFl1Hz8q4o8Qct3isdVN5P475dXaNGiN02HElZMO813uepDRUSJlAfP8AmZIKkxokxEFIUqspvbCpXAZT82xg5gv5C2JY3aVvNwR7pcLR0CmvnJ1AuseqQceKDdEGit1pnoCP6gEeoUQdik97tOl7459V8d3UTpxLozUVlwPU00tgPmUUek8j1tPAmWx17e6EaoLRkK4QeDyWHPA4eu0hBtLQVVtv2Tf61VNTh+D/cv++eJQUArC4IuoqdLYFjB2r+bNKdstjuH+qLGhHuOKDf/+RGG5rHBSRHPmJqJCSqBzmAd2s0/nPAgMBAAGjRTBDMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTDgwKdvAPqbbCmehDaw0PwavI83jANBgkqhkiG9w0BAQsFAAOCAQEAOUcKqpzNQ6lr0PbDSsnsD6onfi+8j3TD0xG0zBSf+8G4zs8Zb6vzzQ5qHKgfr4aeen8Pw0cw2KKUJ2dFaBqjn3/6/MIZbgaBvXKUbmY8xCxKQ+tOFc3KWIu4pSaO50tMPJjU/lP35bv19AA9vs9MTKY2qLf88bmoNYT3W8VSDcB58KBHa7HVIPx7BUUtSyb2N2Jqx5AOiYy4NarhB3hVftkZBmCzi2Qw50KWIgTFYcIVeRTx3Js/F0IuEdgZHBK2gmO7fdM7+QKYm83401vlYRNCXfIZ0H9E1V3NddqJuqIutdUajckSzMhXdNCJqfI4FAQAymTWGL3/lZyr/30xFg=="
        )
        val rootCert = X509CertUtils.parse(encodedRootCert.decode())
        val encodedAcsCerts = listOf(
            Base64(
                "MIIDeTCCAmGgAwIBAgIQbS4C4BSig7uuJ5uDpeT4WDANBgkqhkiG9w0BAQsFADBHMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEXMBUGA1UEAwwOUlNBIEV4YW1wbGUgRFMwHhcNMTcxMTIxMTE1NDAyWhcNMjcxMjMxMTMzMDAwWjBIMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEYMBYGA1UEAwwPUlNBIEV4YW1wbGUgQUNTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkNrPIBDXMU6fcyv5i+QHQAQ+K8gsC3HJb7FYhYaw8hXbNJa+t8q0lDKwLZgQXYV+ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s+hwx1IU5AT+AIelNqBgcF2vE5W25/SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8+lh4oVB07bkac6LQdHpJUUySH/Er20DXx30Kyi97PciXKTS+QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy+7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfwIDAQABo2AwXjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQUktwf6ZpTCxjYKw/BLW6PeiNX4swwHwYDVR0jBBgwFoAUw4MCnbwD6m2wpnoQ2sND8GryPN4wDQYJKoZIhvcNAQELBQADggEBAGuNHxv/BR6j7lCPysm1uhrbjBOqdrhJMR/Id4dB2GtdEScl3irGPmXyQ2SncTWhNfsgsKDZWp5Bk7+Otnty0eNUMk3hZEqgYjxhzau048XHbsfGvoJaMGZZNTwUvTUz2hkkhgpx9yQAKIA2LzFKcgYhelPu4GW5rtEuxu3IS6WYy3D1GtF3naEWkjUra8hQOhOl2S+CYHmRd6lGkXykVDajMgd2AJFzXdKLxTt0OYrWDGlUSzGACRBCd5xbRmATIldtccaGqDN1cNWv0I/bPN8EpKS6B0WaZcPasItKWpDC85Jw1GrDxdhwoKHoxtSG+odiTwB5zLbrn2OsRE5bV7E="
            )
        )

        val jwsValidator = create(true, emptyList())
        assertThat(
            jwsValidator.isCertificateChainValid(encodedAcsCerts, listOf(rootCert))
        ).isTrue()
    }

    @Test
    fun isCertificateChainValid_withSampleCertsAndMastercardRootCert_shouldReturnFalse() {
        val encodedAcsCerts = listOf(
            Base64(
                "MIIDeTCCAmGgAwIBAgIQbS4C4BSig7uuJ5uDpeT4WDANBgkqhkiG9w0BAQsFADBHMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEXMBUGA1UEAwwOUlNBIEV4YW1wbGUgRFMwHhcNMTcxMTIxMTE1NDAyWhcNMjcxMjMxMTMzMDAwWjBIMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBsZTEYMBYGA1UEAwwPUlNBIEV4YW1wbGUgQUNTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkNrPIBDXMU6fcyv5i+QHQAQ+K8gsC3HJb7FYhYaw8hXbNJa+t8q0lDKwLZgQXYV+ffWxXJv5GGrlZE4GU52lfMEegTDzYTrRQ3tepgKFjMGg6Iy6fkl1ZNsx2gEonsnlShfzA9GJwRTmtKPbk1s+hwx1IU5AT+AIelNqBgcF2vE5W25/SGGBoaROVdUYxqETDggM1z5cKV4ZjDZ8+lh4oVB07bkac6LQdHpJUUySH/Er20DXx30Kyi97PciXKTS+QKXnmm8ivyRCmux22ZoPUind2BKC5OiG4MwALhaL2Z2k8CsRdfy+7dg7z41Rp6D0ZeEvtaUp4bX4aKraL4rTfwIDAQABo2AwXjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDAdBgNVHQ4EFgQUktwf6ZpTCxjYKw/BLW6PeiNX4swwHwYDVR0jBBgwFoAUw4MCnbwD6m2wpnoQ2sND8GryPN4wDQYJKoZIhvcNAQELBQADggEBAGuNHxv/BR6j7lCPysm1uhrbjBOqdrhJMR/Id4dB2GtdEScl3irGPmXyQ2SncTWhNfsgsKDZWp5Bk7+Otnty0eNUMk3hZEqgYjxhzau048XHbsfGvoJaMGZZNTwUvTUz2hkkhgpx9yQAKIA2LzFKcgYhelPu4GW5rtEuxu3IS6WYy3D1GtF3naEWkjUra8hQOhOl2S+CYHmRd6lGkXykVDajMgd2AJFzXdKLxTt0OYrWDGlUSzGACRBCd5xbRmATIldtccaGqDN1cNWv0I/bPN8EpKS6B0WaZcPasItKWpDC85Jw1GrDxdhwoKHoxtSG+odiTwB5zLbrn2OsRE5bV7E="
            )
        )

        val jwsValidator = create(true, emptyList())
        assertThat(
            jwsValidator.isCertificateChainValid(encodedAcsCerts, MASTERCARD_ROOT_CERTS)
        ).isFalse()
    }

    @Test
    fun createKeyStore_shouldCreateOrderedAliases() {
        val aliasesEnumeration = DefaultJwsValidator.createKeyStore(
            listOf(
                MASTERCARD_ROOT_CERT,
                MASTERCARD_ROOT_CERT,
                MASTERCARD_ROOT_CERT
            )
        ).aliases()

        assertThat(
            aliasesEnumeration.toList().toSet()
        ).containsExactly(
            "ca_0",
            "ca_1",
            "ca_2"
        )
    }

    @Ignore("Ignore tests with expired certificates")
    @Test
    fun getPayload_withRealJws_shouldReturnExpectAcsData() {
        val jwsValidator = create(true, MASTERCARD_ROOT_CERTS)
        val payload = jwsValidator.getPayload(MASTERCARD_ACS_JWS)
        val acsData = DefaultAcsDataParser(FakeErrorReporter()).parse(payload)

        assertThat(acsData.acsUrl)
            .isEqualTo("https://secure5.arcot.com/acs/api/tds2/txn/app/v1/creq")
        assertThat(acsData.acsEphemPubKey.encoded)
            .hasLength(311)
        assertThat(acsData.sdkEphemPubKey.encoded)
            .hasLength(311)
    }

    @Ignore("MOBDEVPROD-4")
    @Test
    fun isCertificateChainValid_withDiscoverCerts_shouldReturnTrue() {
        val jwsValidator = create(true, emptyList())
        assertThat(
            jwsValidator.isCertificateChainValid(
                encodedChainCerts = DISCOVER_CERT_CHAIN,
                rootCerts = listOf(DISCOVER_ROOT_CERT)
            )
        ).isTrue()
    }

    @Test
    fun `isCertificateChainValid() with empty encoded chain certs should fail and report error`() {
        val jwsValidator = create(true, emptyList())

        assertThat(
            jwsValidator.isCertificateChainValid(
                encodedChainCerts = emptyList(),
                rootCerts = listOf(DISCOVER_ROOT_CERT)
            )
        ).isFalse()

        verify(errorReporter)
            .reportError(
                argWhere {
                    it is IllegalArgumentException &&
                        it.message == "JWSHeader's X.509 certificate chain is null or empty"
                }
            )
    }

    @Test
    fun `isCertificateChainValid() with empty root certs should fail and report error`() {
        val jwsValidator = create(true, emptyList())

        assertThat(
            jwsValidator.isCertificateChainValid(
                encodedChainCerts = DISCOVER_CERT_CHAIN,
                rootCerts = emptyList()
            )
        ).isFalse()

        verify(errorReporter)
            .reportError(
                argWhere {
                    it is IllegalArgumentException &&
                        it.message == "Root certificates are empty"
                }
            )
    }

    @Test
    fun `sanitizeHeader should remove JWK`() {
        val jwsHeader = JWSHeader.Builder(JWSObject.parse(JWS_ES256).header)
            .jwk(
                JWK.parse(
                    """
                    {
                        "kty": "EC",
                        "crv": "P-256",
                        "x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
                        "y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
                        "kid": "Public key used in JWS spec Appendix A.3 example"
                    }
                    """.trimIndent()
                )
            )
            .build()
        assertThat(jwsHeader.jwk)
            .isNotNull()

        assertThat(DefaultJwsValidator.sanitizedJwsHeader(jwsHeader).jwk)
            .isNull()
    }

    private fun create(
        isLiveMode: Boolean,
        rootCerts: List<X509Certificate>
    ): DefaultJwsValidator {
        return DefaultJwsValidator(
            isLiveMode,
            rootCerts,
            errorReporter
        )
    }

    private companion object {
        private const val JWS_P256 = "eyJ4NWMiOlsiTUlJRWhEQ0NBbXdDRkdBR1wvK1NZSVwvN09RMWFFb3FFYlVTaDMwVUdyTUEwR0NTcUdTSWIzRFFFQkN3VUFNSHd4Q3pBSkJnTlZCQVlUQWs1TU1Ta3dKd1lEVlFRS0RDQlZUQ0JVY21GdWMyRmpkR2x2YmlCVFpXTjFjbWwwZVNCa2FYWnBjMmx2YmpFZ01CNEdBMVVFQ3d3WFZVd2dWRk1nTTBRdFUyVmpkWEpsSUZKUFQxUWdRMEV4SURBZUJnTlZCQU1NRjFWTUlGUlRJRE5FTFZObFkzVnlaU0JTVDA5VUlFTkJNQjRYRFRFNU1ESXhPVEV3TkRJek1Gb1hEVEl3TURJeE9URXdOREl6TUZvd2dZQXhDekFKQmdOVkJBWVRBazVNTVNrd0p3WURWUVFLRXlCVlRDQlVjbUZ1YzJGamRHbHZiaUJUWldOMWNtbDBlU0JrYVhacGMybHZiakVZTUJZR0ExVUVDeE1QVlV3Z1ZGTWdNMFF0VTJWamRYSmxNU3d3S2dZRFZRUURFeU5oWTNNdGJYVjBkV0ZzTFROa2N5NXpaV3htZEdWemRIQnNZWFJtYjNKdExtTnZiVENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFJaW5nUmhadHZFWG9Ca0VIT0wrbERXdnRhSVUwTmlWNyszUFwvOG9lTTVrSXh2SGd3alwvVkpJM3VkRXR0YzNzeEJ4RVF2UEE2b3ROTzNqWFo0ajVqUmwwWDluelY2dE1jbGVlVEVyT0l6R1pmSGFMeW83TjYzQitiU0JrT01nR2RvcFpiU2p3T0Z1TGMxTkpsaWg1c0R6cCtsUHJFMG42MWxBZUNmU004dnkzZmhxRkVcL1BZK1RiUkZOQURxendhckd0MENGZ245RjRTYnFEaHJkcXR1eHhTSWFJc24xWnlYQnhPa3huSDFISGhpR2x5dlRcL3hRbEo4SFRuVlRGN2c3cXhPV0NXY2lnMEpnU0graWdObk1kNFNjcEM1aDdxS1JsVis4XC9sNEc3UVE2QzhWeGhpM09UeCtDb2pudnRFSEplbU5yZjFWMFNhQ1dJc0Q3aTZrUVE5c0NBd0VBQVRBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQWdFQXFcL2dhQVZVVE01UUFySUhZN3JCZ0JvUjJBQ2l2S3h2UktuaHlBQWZ2amtCZ2cxa01SZmRcL0Jicnh5a1wvQzlSbzF1aGRmZ2RXMVJtZFJMbFRNQU44Umlqbml3SnVXaUpsZHU3OFRNT3dhK2xUZ3puM2JrRWJVQ3VWVGtPdCs4Y0dGYmZ5djFSNnRwYnhySnZIUmJWWGhyYk14RVBiNWpZTjlVdTV5RDcyNzNvWEhHXC9VdUkxdmdZckhEbGJhSU42S3NZc2JIb0tyMXYxbVB5SFNLeTZYRHBPVmlHM0tsS1FqV0RcL09vUXNOeUlvYkNCOEc5cFliVWwzaCtnVHB1YXhib0s1SGFcL0d4b0pob1hreFd2NFwveWhyUUhJRkozakxaS3BwNUdRN1wvSHh1dmU3UWRXMmY1ZUxkSU9SUGM0RVh4ZWt0NmpYTWRRaFUzYURWeDNieURsS2E0MXpqdzZ6Q0U4aThaUXIyRm9RcWorc0QzYmxVUzNrcUlVN2R5aTJ5MkpDcDk0emNVb3ArYlpPcjc0Zm9iNDMzOGZOMUFUNFBVQ0VlWnJQUTR6UFdOUVFzVm1wQ3Z4YnRZMFUwZmZKcEpyekVpUHVcL2FLOTc2Mm5WUlFcL1YrVWpuQ2ZNNHV4bklqMkRvOXhxU2FoU3Nhckc4NWcyaDRCSjZpQmt2UU5oZWRqdXhnZnBDb3hCQUQxUHBNc2hBQXJvYkErdFZiWVdJczBpaE41N1N1S1JobHFCMGlmNTFlREp3b281TThBMzBud0ExM1VtbTVDVTBNYW9LdVwvN2hHeEJFSTV3NFExb3RxY2Zmc1Ryc2ZBK3dLTlJGbkxEZXo5WXRzbWZUVW9UbktcL0pkbFdyUExRdEdtMjZTaE8zbVpFQWlNdG92a0pENmNVdXBZaE8wQUVFYkFNPSIsIk1JSUYzakNDQThhZ0F3SUJBZ0lKQUpNdnZlc2ptRHloTUEwR0NTcUdTSWIzRFFFQkN3VUFNSHd4Q3pBSkJnTlZCQVlUQWs1TU1Ta3dKd1lEVlFRS0RDQlZUQ0JVY21GdWMyRmpkR2x2YmlCVFpXTjFjbWwwZVNCa2FYWnBjMmx2YmpFZ01CNEdBMVVFQ3d3WFZVd2dWRk1nTTBRdFUyVmpkWEpsSUZKUFQxUWdRMEV4SURBZUJnTlZCQU1NRjFWTUlGUlRJRE5FTFZObFkzVnlaU0JTVDA5VUlFTkJNQjRYRFRFMk1USXlNREV6TlRBd05Wb1hEVE0yTVRJeE5URXpOVEF3TlZvd2ZERUxNQWtHQTFVRUJoTUNUa3d4S1RBbkJnTlZCQW9NSUZWTUlGUnlZVzV6WVdOMGFXOXVJRk5sWTNWeWFYUjVJR1JwZG1semFXOXVNU0F3SGdZRFZRUUxEQmRWVENCVVV5QXpSQzFUWldOMWNtVWdVazlQVkNCRFFURWdNQjRHQTFVRUF3d1hWVXdnVkZNZ00wUXRVMlZqZFhKbElGSlBUMVFnUTBFd2dnSWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUNEd0F3Z2dJS0FvSUNBUURFZlkyeHVMTmpNOFwvM3hyRzZ6ZDdGYnVYSGZDRmllQkVSUnVHUVNMWU1tRVM1a2hnalp0ZU41OU5lb0RiSXUzWE5GQ200VFIyVFRwVGRqbVNGVThlRDFFMytDWFc5TTZRY3pDb1R1NU9aaCtoNnlPWVRNRWt0K3dEZjNDMGhaZVwvN2pqeTJQb2RpSEhmdWUwU1NaSUpRNVZtNHNVa21FRGJEYmNTZFJsRm14VWUyYXlYM3RsWXl4em1laFpTR1E4am1WaG5XMFhXZzM2bVFKTnN2WDJuTG5CQjU4RUUyR3RHZFg5Ym5LZFhOZlpUQVBTcmRTT25YTVA5N0doK1JwMXVkM1lBbmNLTzRST3ppTlNXanpEb2EwT2Z3bmFKV3N4Mkk2ZGJXQlBTNVFIUVp0blwvdzBpSGF5cFhvVE1lWlVqSVZTcktIeDBaQUhyM3Y2cFVINm95K1E5QjkzOUVsT2ZsT3JhRnlkYWxQazMzaSt0eEI2Qnp5THdsc0RHWmFlSW00SmJscnFseDBReXpRWlwvVDBiYWZiZmxtRnpvZGw2WnZBZ1NENE9uUG81QVE3RGw0RTlYaUlhODVsMGpsYjcxcytYeVwvOXBOQnZzcGQzS0hUdDBiXC9KNWo3c3pSa09idG5pa3JGc0V1NTVIY1I5aHo1ZkVvZm92Y2JrTEJMdk5DTGNacnptaURKaEw2V3NycG8wN1VtWVwvOVRcL0RCbWpOT1RpREtrM2N5XC9OOXNQaldlb2F1eUNmZnNuNnlMbk5MWjRoc0QrSDd2Q3BvUE14eUZ4SmFOT2F3djA4WkYrMTdycUNjdVJwZlBVNlVXTE5DbUNBMWZTTVliY3RPMjhTdFMybzZhY1dGM25ZZHFnblZaQ2cwXC9IMk0zYjVUT2VWbUF1Q1FXRFZBY294Z1FJREFRQUJvMk13WVRBZEJnTlZIUTRFRmdRVW1IWnJob3VDYk1CZ001c0FpREh2MHZBYmVcL0l3SHdZRFZSMGpCQmd3Rm9BVW1IWnJob3VDYk1CZ001c0FpREh2MHZBYmVcL0l3RHdZRFZSMFRBUUhcL0JBVXdBd0VCXC96QU9CZ05WSFE4QkFmOEVCQU1DQVlZd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQkFLUnM1Vm9lYnh1NHl6VE1JYzJuYndzb3hlMFpkQWlSVTQ0QW4zajRnend1cUNpYzgwSzRZbG9pRE9JQWZSV0c3SGJGMWJHMzdvU2ZRQmhSMFgyenZIXC9SOEJWbFNmYXFvdnI3OHJHT3llak5Bc3RmR3BtSWFZVDB6dUUyanZqZVIrWUttRkNvcm5oQm9qbUFMellOUUJiRnBMVUM0NUhlOHo1Z0IyanNudjdsMEhSc1hKR04xMWFVUXZKZ3dqUVRiYzRGYkFuV0lXdkFLY1V0eWVXaUNCdkZ3XC9GVHgyM1pXTVVXOGpNcmpkeWlSYW43ZFhjNm41dkRcL0RWM3R1TTVyTVdFQTV4MDdEOTdEVlwvd3ZzXC9NOEk4REw2bUkydEVQZndWZlwvUUlXNFVPTnBubEFoNmk5RGV2QitzS3JxcmlsWEU5MXBQT0NtQlhZWEJ4YkFQVzhNM0doN2syVlZXXC9qTDRrcW9CNEhmSDBJREhxSVZlU1hpclNIeG92S1wvZkdJcWpFdWVkTFd6TU1LVGNFY1lpN0xWU3FGdkZZVlwva2hpbXVtQWw4U0ZWcEhRc1E3THZzS2ltMUNzdXBrTytmVWI0NGRrYVV1bTZRQ1wvaUluazc4S1JnR1Y4WFpBMjV5dzR3XC9GSmFXZWswam51Q0prN1YrNzdONlBHSzBGeG1TZHJIUk56TlNvVGttYTRQdFpJVG5HTlRHcVhlVFYwSHZyOENsYlFmQldwcWFadEtCOGRUa2hSQ1RVUGFzWVpaTEZ0ajJZMldjWHNoTUJBaEVuQmlDc29hSUd6MXh4Y3lGSDRJb2lDMkdLYmZpNXBqWHJIZlJydFBJcjFCNFwvdVdNSHhJdHRFRkszcUtcLzNWYzFiamRYNkg0SVVXTlY2MlA1Mmt3ZHNNWE5vUTU1anciXSwiYWxnIjoiUFMyNTYifQ.eyJhY3NVUkwiOiJodHRwczpcL1wvc2ltdWxhdG9yLTNkcy5zZWxmdGVzdHBsYXRmb3JtLmNvbVwvdjIuMS4wXC9hY3NcLzk0NlwvIiwiYWNzRXBoZW1QdWJLZXkiOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiJIOHhXWVdBRk43bm92WDlWdV96Ny1rTFZNZ0h3NFpKRzA1dnVFTGhNU3NFIiwieSI6IkNSV0ZFTWM5Q1RYa1oxQ0VETnpqOGNCai1KaVZGUVJNMTdXSXluSG9ZMXMifSwic2RrRXBoZW1QdWJLZXkiOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiJFN2l6VXhrdjN5aFhFbVR3U0NqTFFIZWNzdWE1T2ZHRUxsdFczOWZFN1ljIiwieSI6InVDbGdMTWlwMGpRUGdKakRZR3pMNUpIcjhvLXRfbkZESDVjMnpsUmVvcDAifX0.CAA2X2OM3-u7IM5UQXDnnVKvCBQKMm6pt-SWx1JzQDUO76YnLDqt6kKZWX3F0t00Nmnw_Y1tKYmm0GxDN7epqUJoJHZXIuXOPeUOt3zpXCVFSwiUgeCfq4cKRS1X0KzvL4rEJuekXeom07mJpqv5G34tL40nzvc3TaJt_cApYtng9DE5WlHx8gQrhpRCNPDd67RzTtvQIMyCpyjBQWlADPUW2AUQdTTi4bDz5diHAdDgKu3HZtHhX9NiwyP7bwE62qxCLiHjqfkmI6u6EH3HleUd0iQ23Gvz34RYd6heHJhhaOo--vk30Gt6CgoAmQZVt--RDgCDEuqEZJ3OlUlCJg"

        private const val JWS_ES256 = "eyJ4NWMiOlsiTUlJRHVUQ0NBYUVDRkdBR1wvK1NZSVwvN09RMWFFb3FFYlVTaDMwVUdzTUEwR0NTcUdTSWIzRFFFQkN3VUFNSHd4Q3pBSkJnTlZCQVlUQWs1TU1Ta3dKd1lEVlFRS0RDQlZUQ0JVY21GdWMyRmpkR2x2YmlCVFpXTjFjbWwwZVNCa2FYWnBjMmx2YmpFZ01CNEdBMVVFQ3d3WFZVd2dWRk1nTTBRdFUyVmpkWEpsSUZKUFQxUWdRMEV4SURBZUJnTlZCQU1NRjFWTUlGUlRJRE5FTFZObFkzVnlaU0JTVDA5VUlFTkJNQjRYRFRFNU1ESXhPVEV3TkRNek5Wb1hEVEl3TURJeE9URXdORE16TlZvd2dZQXhDekFKQmdOVkJBWVRBazVNTVNrd0p3WURWUVFLRXlCVlRDQlVjbUZ1YzJGamRHbHZiaUJUWldOMWNtbDBlU0JrYVhacGMybHZiakVZTUJZR0ExVUVDeE1QVlV3Z1ZGTWdNMFF0VTJWamRYSmxNU3d3S2dZRFZRUURFeU5oWTNNdGJYVjBkV0ZzTFROa2N5NXpaV3htZEdWemRIQnNZWFJtYjNKdExtTnZiVEJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCTmhIUThvVTExeXA5cEtcL0VaVStLZWpybDl2ZkJYOGpZUXJHZFlxU3I4SHlmOEVCYzU1QzV3ZGh3dUU5c3JWZk5BUlVHaVNMbjJUYUpqcFZDNHFGOThnd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQkFDckJobXM5emdBZ3pVV3RINWlQYzdhelluZ3g1cmVMNFFQMVpMeUE5RUlVVkdnclBOWGhOTDNUTmpVRkNOUm9lbjhuSXU3eHBUM0oyQ3dWQjVYVkpUN0pxczVKUHJRQ1lBZUgzUmpUOU82MmFhNVhaak5ZTm05c0R3dWJcL2JIdjZJdTFJWmVFZURYM1dPWFpacXpwaFFpYW9NUVBoaTFncjV4WXZrV1ZKbnN4R3NJdmR6MkYrRm5XbExtR0RRVDVFYmRKSHhJKzRoM1FLdUhVYnBSeWN4bHkyVWRsT29CeUpIbHNmaXErcmNcL2tCUjI4UWdOU3l3ZlR3OVAzUTFUTDZtWlo5ck1BOWxJdEZZZ1ZZUklpRjJPalhmK2JHVG1jbXljY0NvSHQ1V3NPSnFGcHV1YndQS3U5Um5UamF0ckNrT29nR0JBOHorS0VBQkZEeXZGbDJ1MDN3d0RQVDd0T2N3bVBFWjNZaGNTT0VYak1vVDV1UWdqMVJkblMzWWZZS1VMVk9zUzBISTliOTJVXC9HbFJMaFJzRktYZFU4cTh5NWQ1SjhKMzFTNHJ5dDVBbHlZaFRqOXFuaFB2aE9CTXNIelhuZ2V0VFwvTXNuMVZROFZ4QUNRR2lHMHl2Y3FBdzdtXC9aNmpTbWxzSTBiUzdZTm1RMUZOR0pGdDRFQitxdXB5bzZqd1h1Qm9NOXA0OWpQK2JFanJwd1l2ck9tbElkeG92TkVQZWRPQlVRcVwvc3F2QWJVdmwwQVhhdmpLOFdJSG15OHhiek9wUXJEdGYxTEtKY09IbmtoTHdGUzJubWY3bnAwNUpDNWxzN2V6ZkxtWTFQdUIrdzg5MCswR0o3XC9nVDVFaUZTV09BRmlBYWltc3B1aUgwdEVpZ0RSa2NubE1nR3pVKzR1c2p3XC9PIiwiTUlJRjNqQ0NBOGFnQXdJQkFnSUpBSk12dmVzam1EeWhNQTBHQ1NxR1NJYjNEUUVCQ3dVQU1Id3hDekFKQmdOVkJBWVRBazVNTVNrd0p3WURWUVFLRENCVlRDQlVjbUZ1YzJGamRHbHZiaUJUWldOMWNtbDBlU0JrYVhacGMybHZiakVnTUI0R0ExVUVDd3dYVlV3Z1ZGTWdNMFF0VTJWamRYSmxJRkpQVDFRZ1EwRXhJREFlQmdOVkJBTU1GMVZNSUZSVElETkVMVk5sWTNWeVpTQlNUMDlVSUVOQk1CNFhEVEUyTVRJeU1ERXpOVEF3TlZvWERUTTJNVEl4TlRFek5UQXdOVm93ZkRFTE1Ba0dBMVVFQmhNQ1Rrd3hLVEFuQmdOVkJBb01JRlZNSUZSeVlXNXpZV04wYVc5dUlGTmxZM1Z5YVhSNUlHUnBkbWx6YVc5dU1TQXdIZ1lEVlFRTERCZFZUQ0JVVXlBelJDMVRaV04xY21VZ1VrOVBWQ0JEUVRFZ01CNEdBMVVFQXd3WFZVd2dWRk1nTTBRdFUyVmpkWEpsSUZKUFQxUWdRMEV3Z2dJaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQ0R3QXdnZ0lLQW9JQ0FRREVmWTJ4dUxOak04XC8zeHJHNnpkN0ZidVhIZkNGaWVCRVJSdUdRU0xZTW1FUzVraGdqWnRlTjU5TmVvRGJJdTNYTkZDbTRUUjJUVHBUZGptU0ZVOGVEMUUzK0NYVzlNNlFjekNvVHU1T1poK2g2eU9ZVE1Fa3Qrd0RmM0MwaFplXC83amp5MlBvZGlISGZ1ZTBTU1pJSlE1Vm00c1VrbUVEYkRiY1NkUmxGbXhVZTJheVgzdGxZeXh6bWVoWlNHUThqbVZoblcwWFdnMzZtUUpOc3ZYMm5MbkJCNThFRTJHdEdkWDlibktkWE5mWlRBUFNyZFNPblhNUDk3R2grUnAxdWQzWUFuY0tPNFJPemlOU1dqekRvYTBPZnduYUpXc3gySTZkYldCUFM1UUhRWnRuXC93MGlIYXlwWG9UTWVaVWpJVlNyS0h4MFpBSHIzdjZwVUg2b3krUTlCOTM5RWxPZmxPcmFGeWRhbFBrMzNpK3R4QjZCenlMd2xzREdaYWVJbTRKYmxycWx4MFF5elFaXC9UMGJhZmJmbG1Gem9kbDZadkFnU0Q0T25QbzVBUTdEbDRFOVhpSWE4NWwwamxiNzFzK1h5XC85cE5CdnNwZDNLSFR0MGJcL0o1ajdzelJrT2J0bmlrckZzRXU1NUhjUjloejVmRW9mb3ZjYmtMQkx2TkNMY1pyem1pREpoTDZXc3JwbzA3VW1ZXC85VFwvREJtak5PVGlES2szY3lcL045c1BqV2VvYXV5Q2Zmc242eUxuTkxaNGhzRCtIN3ZDcG9QTXh5RnhKYU5PYXd2MDhaRisxN3JxQ2N1UnBmUFU2VVdMTkNtQ0ExZlNNWWJjdE8yOFN0UzJvNmFjV0YzbllkcWduVlpDZzBcL0gyTTNiNVRPZVZtQXVDUVdEVkFjb3hnUUlEQVFBQm8yTXdZVEFkQmdOVkhRNEVGZ1FVbUhacmhvdUNiTUJnTTVzQWlESHYwdkFiZVwvSXdId1lEVlIwakJCZ3dGb0FVbUhacmhvdUNiTUJnTTVzQWlESHYwdkFiZVwvSXdEd1lEVlIwVEFRSFwvQkFVd0F3RUJcL3pBT0JnTlZIUThCQWY4RUJBTUNBWVl3RFFZSktvWklodmNOQVFFTEJRQURnZ0lCQUtSczVWb2VieHU0eXpUTUljMm5id3NveGUwWmRBaVJVNDRBbjNqNGd6d3VxQ2ljODBLNFlsb2lET0lBZlJXRzdIYkYxYkczN29TZlFCaFIwWDJ6dkhcL1I4QlZsU2ZhcW92cjc4ckdPeWVqTkFzdGZHcG1JYVlUMHp1RTJqdmplUitZS21GQ29ybmhCb2ptQUx6WU5RQmJGcExVQzQ1SGU4ejVnQjJqc252N2wwSFJzWEpHTjExYVVRdkpnd2pRVGJjNEZiQW5XSVd2QUtjVXR5ZVdpQ0J2RndcL0ZUeDIzWldNVVc4ak1yamR5aVJhbjdkWGM2bjV2RFwvRFYzdHVNNXJNV0VBNXgwN0Q5N0RWXC93dnNcL004SThETDZtSTJ0RVBmd1ZmXC9RSVc0VU9OcG5sQWg2aTlEZXZCK3NLcnFyaWxYRTkxcFBPQ21CWFlYQnhiQVBXOE0zR2g3azJWVldcL2pMNGtxb0I0SGZIMElESHFJVmVTWGlyU0h4b3ZLXC9mR0lxakV1ZWRMV3pNTUtUY0VjWWk3TFZTcUZ2RllWXC9raGltdW1BbDhTRlZwSFFzUTdMdnNLaW0xQ3N1cGtPK2ZVYjQ0ZGthVXVtNlFDXC9pSW5rNzhLUmdHVjhYWkEyNXl3NHdcL0ZKYVdlazBqbnVDSms3Vis3N042UEdLMEZ4bVNkckhSTnpOU29Ua21hNFB0WklUbkdOVEdxWGVUVjBIdnI4Q2xiUWZCV3BxYVp0S0I4ZFRraFJDVFVQYXNZWlpMRnRqMlkyV2NYc2hNQkFoRW5CaUNzb2FJR3oxeHhjeUZINElvaUMyR0tiZmk1cGpYckhmUnJ0UElyMUI0XC91V01IeEl0dEVGSzNxS1wvM1ZjMWJqZFg2SDRJVVdOVjYyUDUya3dkc01YTm9RNTVqdyJdLCJhbGciOiJFUzI1NiJ9.eyJhY3NVUkwiOiJodHRwczpcL1wvc2ltdWxhdG9yLTNkcy5zZWxmdGVzdHBsYXRmb3JtLmNvbVwvdjIuMS4wXC9hY3NcLzk0NlwvIiwiYWNzRXBoZW1QdWJLZXkiOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiIyQlB0bjJYcUt2MnNVZm9jVjJnbTFVeGhHUlEtd2Z4aFE4aUpCcFI4ekw4IiwieSI6InFtWmV3QlZBcVFyX3JVc1NGT3pZbUxKeURwaWVOLTF3UlJGdjlJVUpKQVUifSwic2RrRXBoZW1QdWJLZXkiOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiItUFJHZXlGWFYyZHYzaWJqM2xpMUhOZXBGTU9Cd3NqVTlzV3JWNm1pako4IiwieSI6IkJ4Rm1xZVJNdzJrU3dGTXZJaHBRVzdCcEJISlN2N21qXzhmQ1FzMDBONmsifX0.VTGAS4oT077dS3CitbHIBLcKpHmdSFOji9Ky2-_FeFKxLVnR6GJ2VxzbavlSnWSiNl9Ai_lIeZTpXuyXOYrEeA"

        private const val UNSIGNED_JWS = "eyJhbGciOiJFUzI1NiJ9.eyJhY3NFcGhlbVB1YktleSI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjNoU0tOdml0STVrVUtkVGVHSUZjSFJ1cjNlSGx1ZEEtaDRPbTA0djZUd2MiLCJ5IjoicWpoSjlISTFDZWN3SFktSmRqNXozWXIyNXVCLXZFakU2S3djRExhSTA5YyJ9LCJzZGtFcGhlbVB1YktleSI6eyJrdHkiOiJFQyIsInVzZSI6InNpZyIsImNydiI6IlAtMjU2Iiwia2lkIjoiM2ZlMGNiMjAtNDhiZi00NGY5LTk5YWUtMTI2OTFlYmQwMzgyIiwieCI6IkpQdWhiSTRpaTd6MVg4U1RpVU9FVTVsWTdqaHFYMk1zV1NnN3RIbU5RUFEiLCJ5IjoiU2txSDJPMmlwbUJzS2F4czN3SnpDbC0wNDlkR2xTQXA3QS1kcnVSTlJuTSJ9LCJhY3NVUkwiOiJodHRwczovL2hvb2tzLnN0cmlwZS5jb20vM2Rfc2VjdXJlXzJfdGVzdC9hcHBfY2hhbGxlbmdlL2hCbUR6MlFSWTNVTlBQU1N5QWRNTXQxSXNYZWN3YzhVNlRlckJiNEJfY289In0.aER-DQLnhHTjReHDkneOlDjVUcxg_TZjv41X6VjpKvzOcEpwPzxDo6xFTYONNoQbjK3j8Q9YTzX4jLjup2cWSQ"

        private const val MASTERCARD_ACS_JWS = "eyJ4NWMiOlsiTUlJRndqQ0NBNnFnQXdJQkFnSVFmcnRHRlVEQnF0Q2dxK01ZQ1QwSWJ6QU5CZ2txaGtpRzl3MEJBUXNGQURCNE1Rc3dDUVlEVlFRR0V3SlZVekVUTUJFR0ExVUVDaE1LVFdGemRHVnlRMkZ5WkRFb01DWUdBMVVFQ3hNZlRXRnpkR1Z5UTJGeVpDQkpaR1Z1ZEdsMGVTQkRhR1ZqYXlCSFpXNGdNekVxTUNnR0ExVUVBeE1oVUZKRUlFMWhjM1JsY2tOaGNtUWdNMFJUTWlCSmMzTjFaWElnVTNWaUlFTkJNQjRYRFRFNE1EZ3hNekE0TWpnMU9Gb1hEVEl3TURneE1qQTRNRGd4Tmxvd2dha3hDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saE1SUXdFZ1lEVlFRSEV3dFRZVzUwWVNCRGJHRnlZVEVhTUJnR0ExVUVDaE1SUVhKamIzUWdVM2x6ZEdWdGN5Qk1URU14TURBdUJnTlZCQXNUSjBGRFUwMVRMVUZEVXkxV01qRXdMVU5CWDFSRlEwaE9UMHhQUjBsRlV5MHlNalF5TVMxRFFURWhNQjhHQTFVRUF4TVljMlZqZFhKbE5YTnBaMjVwYm1jdVlYSmpiM1F1WTI5dE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBdXEzWjk5WHJXOFFmY05Yd1BhZEtJMjFuY0RLWDVFNWJLQ0M1MGFqdG5Pb3g0Zlh3SWxtcXhBQW9kY2IrdTUrQnFxXC9LaDFDMDlZTGpEdm9ablZ1R1BaenN6Rks5UzhiOUViemNvdGhnNjJkXC9Eb1ZOUUE0RDRRYkNQeHI5Ulk2VGh0OEIrVElVVlJveTVmQjNDakpmSTNvalZuZ3JDbGNzOTNZZXBrbUxod1VJcGdNckdhRWJcL1B1TnB5XC9VN29yUktjR0lSRjY4Q0J0eVNxWUxLM1M2SUdJMkJJVlBCakdFeUcyZHdDNTFaN0YwM2NPZkVBMTY3RENES3BKNG9KTE1IMklJY0srRTg3OU1QakNEcVJ4b09ubXdzczQwTVNlQ1lYTGVJOUYwWndkd0oycitNN0RaellPaEp2OWFia1Z4WFRjS1wvRStrWng2em5jeXgzQndIM3dJREFRQUJvNElCRkRDQ0FSQXdEZ1lEVlIwUEFRSFwvQkFRREFnZUFNQWtHQTFVZEV3UUNNQUF3SHdZRFZSMGpCQmd3Rm9BVVRcL2ZEbjJMS1ZsUkwzMGgweTNBY2J6emRFRVV3U0FZSUt3WUJCUVVIQVFFRVBEQTZNRGdHQ0NzR0FRVUZCekFCaGl4b2RIUndPaTh2YjJOemNDNXdhMmt1YVdSbGJuUnBkSGxqYUdWamF5NXRZWE4wWlhKallYSmtMbU52YlRCcEJnTlZIUjhFWWpCZ01GNmdYS0JhaGxob2RIUndPaTh2WTNKc0xuQnJhUzVwWkdWdWRHbDBlV05vWldOckxtMWhjM1JsY21OaGNtUXVZMjl0THpSbVpqZGpNemxtTmpKallUVTJOVFEwWW1SbU5EZzNOR05pTnpBeFl6Wm1NMk5rWkRFd05EVXVZM0pzTUIwR0ExVWREZ1FXQkJROW5ORUxWenMrcGhCSEt3YitwZnpyRmFjOVB6QU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FnRUFFY3kwUDJxZU84bnhmMVJwTzJRb3Vyc0dWb285ODBxOE9KejYxcFE4ekJSKytQcVNTenZCNnFoeXlDUkFKWXNWeThXRFM5dmRRc05vTHQ2RDNvc0ZIK1BKdHVRUFIzdkljNFRFalwvSHZwYktWY3VYdUtOQzZnck1oR1VBOTRERjFDRk1UK2szbnVjNVd2TXJDT1NCMnl4RWZvaFwvcjI4akdHbDRabjZ6NlMwZm9WZ2R4cWZKMjIzWmo4UTQwSXdrKzJUalRTcVhFbEJQQTJvTjVvQ1lCbStsZXg0ZmNwb2I1UGlucVoySDVSU21GeFwveEtacnN3aUFMaVNuelM5QzdEMFVQQ0hUVXpZb2xXZjcrdnZKSFpBREZOVWcxdlwvV2VOUGZFQ1FPWkFtSEthUGJQRCthcUlaSWU3QVVpTkJiVXhIKzFzOTVSa2tYMmRKNWtkOWRuWWxFMWtqRHdSXC8wV3JIXC9cL1h0aFZmOVdFTHlCOU1zcmF2TzNyUDdZaWt5RjdvczVpbCtEODZFaWJzcEd0R1IrYjF4RVM3UFk2c0poQm8wQlJFd3VnbDNvSzdESUJpQkdTOEJuSXIzSkxvankzeTVCQWdDcVRYazJcL1BXSkZjN3gzWWhZek1UNmkyRnF0SWg4cWtoaUtndXpNdDlSdVByQm9qME5nMHRxbUQzaUJsV0ZwYWJOcTFpbCtaRmNaMm9Wbko4WEU2WmVRWWFKYUw5WE1SVHE5YlJxUlpxVURBb2hpa1FHaTZCRDlibXNsUmlyaTVFdEdyeXF5MGhoWG53dVBHc2xUc05ubzRPNHU3ZHk2WTBZbThlNGVVVG1uTnRneDVrYlNQbW45TzZmUTRhMEtJYXArQTJkdEJtdXBUY0Z0OTJsVzJFT2hzSTM3WDJyUEl3SmVPUEZVPSIsIk1JSUduVENDQklXZ0F3SUJBZ0lRQ1dYQWdpV1wveFF1NldRR2kwbEh4S1RBTkJna3Foa2lHOXcwQkFRc0ZBREI4TVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNoTUtUV0Z6ZEdWeVEyRnlaREVvTUNZR0ExVUVDeE1mVFdGemRHVnlRMkZ5WkNCSlpHVnVkR2wwZVNCRGFHVmpheUJIWlc0Z016RXVNQ3dHQTFVRUF4TWxVRkpFSUUxaGMzUmxja05oY21RZ1NXUmxiblJwZEhrZ1EyaGxZMnNnVW05dmRDQkRRVEFlRncweE56QXhNREV3TlRBd01EQmFGdzB5TmpBM01UVXdOekF3TURCYU1IZ3hDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFLRXdwTllYTjBaWEpEWVhKa01TZ3dKZ1lEVlFRTEV4OU5ZWE4wWlhKRFlYSmtJRWxrWlc1MGFYUjVJRU5vWldOcklFZGxiaUF6TVNvd0tBWURWUVFERXlGUVVrUWdUV0Z6ZEdWeVEyRnlaQ0F6UkZNeUlFbHpjM1ZsY2lCVGRXSWdRMEV3Z2dJaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQ0R3QXdnZ0lLQW9JQ0FRQ2JEV3o1NWg4WWhVdEhqczgzeVRwb0ZOYlVnSXZuUGNKVFNFVXBpaUNMZWRpY2g2MURwUVhmOG5CSWRVRnYrenM3akVLUytsTmNaeDc1aVV3R0oybVJvUk5pa0pqN25LV3dJUEdTcmhzSmVPR1Jud2tnNmtoOVBFRU5SZ1V5bDZETVVza1BZaFo5K0tOZXVIcnQzSGUrc2ZCYmxLXC9SUTNKUnN5TlY5Mll0TVBCQWsyTmRkQnZtaDlcL0ZTbnl1MTN3U2hMVWF0eHlzWjY5OE9JWjJicFhzRDJGTzNNajQ5UlhwWFN5TU96Um5XTUIxT0pDY3FaMW5QSmhHM3ZwSDN2YWJUZWhYMmNHTDN4a2FhNklUVzZta3JuZUtqbktvUzNNMzNiUlJlK09nQW5sdW9jWTYrcUpocU1rQ01wRkxRTEdVY25rWGlyRkNLcU1MNU9BSldYUVFnUktGWTJPckRBdWdNUHZzbTR5TlZoRUJvY0h3dzZ1YzY2SnZyRTdUQmt5NkhBOHZJSlgzc1ZVUGwySFwvNUh2VWtWaGtFUndtaFM2S2oyeE5WZHcyMlFVelhjYTV3cHhodTVxemtZS3VFOGZCU1RPaDVXSytBRWZzYnFrWjEwN1VnNitya0xaSUNwK1wvaGJUbkltMG56b0pqc05OdldiSkh4alAwRzJEMzYyUWk2b08zVUtrZDlvc3cyOUNkSFNia2phWXBxQkVrbUMrYzJiQ3FyQVByZUxCV2Q0MWlpcVJlS0ptTWg4eVNcLzMySDl4UEJIaWRQcDBsZjcyQ1IyWlwvQzl0SlBNZ1lVZkVVa2JSdVQ1U1ErMzArVE5JWWxaZ3lMeDV1TFhyelhLenhzQSthZlNuanhTZ21YVXdnZXE2RkhTTDY5UXVIaUZRcktnR0RJRFg2cHJ3SURBUUFCbzRJQkhUQ0NBUmt3U0FZSUt3WUJCUVVIQVFFRVBEQTZNRGdHQ0NzR0FRVUZCekFCaGl4b2RIUndPaTh2YjJOemNDNXdhMmt1YVdSbGJuUnBkSGxqYUdWamF5NXRZWE4wWlhKallYSmtMbU52YlRCcEJnTlZIUjhFWWpCZ01GNmdYS0JhaGxob2RIUndPaTh2WTNKc0xuQnJhUzVwWkdWdWRHbDBlV05vWldOckxtMWhjM1JsY21OaGNtUXVZMjl0TDJRMFlUVTFNV0ZoT1RKa1lURXhPR0l4TkdNMFptWXhNVGRoWlRFeFpHVXhNekZtT1RSaFlqRXVZM0pzTUE0R0ExVWREd0VCXC93UUVBd0lCaGpBU0JnTlZIUk1CQWY4RUNEQUdBUUhcL0FnRUFNQjBHQTFVZERnUVdCQlJQOThPZllzcFdWRXZmU0hUTGNCeHZQTjBRUlRBZkJnTlZIU01FR0RBV2dCVFVwVkdxa3RvUml4VEVcL3hGNjRSM2hNZmxLc1RBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQWdFQW0wMkJ2NmlJXC9aa3ZzcjZkQUdcL2dpSkNPK3BldkRIODBXR2hhZ3Z2eWVJY2pJd3dmc1NJVWI5dzM1WFJSaENPa3hTblA3bHVZbW5PY29qdlNERW5lVVZiU3NNeDlcL3pxXC9SMUJsXC9Gd0FJa3N6SkFjZ3hOaDFwXC80SDlqSlRWRkUwVDFKbDZDMVkwb0YrWDBmaFV4UXBIMUZZQlhBNFdaVCs3UkRHXC8zM09EOG5kQlRPd291ZWhcL040RXdGWmw4UjRrMUZyZGVhUm5tdXhTb0lJa2J2NklkZFZNM09nVE1OWHJpNGNOUDNIMmpwaTE0QmdoYld5M1YyODI0aG9EV3dmVm83U01iUDFNeG9Yb281SFdwRUVvdWt0UVhYak5EWVl0ZEZZUVdEbWxyNkZoZUFIMVFudXp0d3hkODc4XC9DOUR2Y3VzdVY4SFB0QUZRVlZqc1hvM2dJY3RuNU5EQStjelh2d2RZY2grU3FaYm01WXZiTVQ5UkpZem5aQXNTM2ZEXC9zZFp1VGdqMzBtWTEyZitKdWdoTEtheXpldHg1T09vR29UcVFQRm5rMEo4cis0aWN3UU5LTnhOdkhUTmhEVmtQVXNvZVwvWjA3NmVkdjJyQ1g0dHlWYVhyVlo1MEswNGZWN2swSGdWSWxRellFWWVRODRsbklidU1lTVo3MGJnK0VhTk5OWnVvZGZIdXZVUWtlMlwvR1FHM0Q3NVZZTWN3cWRBQUdINkp3NU9kbkQ3TTRXXC9LaEVuSXpqOWNqb1pnTnRZYktXRk5vdWF0NGdQbjNiR2xJbmZacHJrRzJDRXBJbElacDJxVk1sVDg1ZmFnREZqb2k4SHNzZlFtYm00R0JPc0NPUDV0T3RvWVVqaHdlYTQyOTdDT24ybnk2d0MyN1ZEbGM2T21uRDJUOD0iLCJNSUlGeHpDQ0E2K2dBd0lCQWdJUUZzanlJdXFodzgwd05NalhVNDdsZmpBTkJna3Foa2lHOXcwQkFRc0ZBREI4TVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNoTUtUV0Z6ZEdWeVEyRnlaREVvTUNZR0ExVUVDeE1mVFdGemRHVnlRMkZ5WkNCSlpHVnVkR2wwZVNCRGFHVmpheUJIWlc0Z016RXVNQ3dHQTFVRUF4TWxVRkpFSUUxaGMzUmxja05oY21RZ1NXUmxiblJwZEhrZ1EyaGxZMnNnVW05dmRDQkRRVEFlRncweE5qQTNNVFF3TnpJME1EQmFGdzB6TURBM01UVXdPREV3TURCYU1Id3hDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFLRXdwTllYTjBaWEpEWVhKa01TZ3dKZ1lEVlFRTEV4OU5ZWE4wWlhKRFlYSmtJRWxrWlc1MGFYUjVJRU5vWldOcklFZGxiaUF6TVM0d0xBWURWUVFERXlWUVVrUWdUV0Z6ZEdWeVEyRnlaQ0JKWkdWdWRHbDBlU0JEYUdWamF5QlNiMjkwSUVOQk1JSUNJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBZzhBTUlJQ0NnS0NBZ0VBeFpGM25DRWlUOFhGRmFxKzNCUFQwY01EbFdFNzZJQnNkeDI3dzNoTHh3VkxvZzQyVVRhc0lnem15c1RLcEJjMTdIRVp5TkFxazlHckNIbzBPeWs0Slp1WEhvVzgwZ29aYVIyc01ubjQ5eXR0N2FHc0UxUHNmVnVwOGdxQW9yZm0zSUZhYjJcL0NuaUpKTlhhV1Bnbjk0K1VcL25zb2FxVFE2ais2SkJvSXduRmtsaGJYSGZLcnFsa1VaSkNZYVdiWlJpUTdua0FOWVlNMlRkM044N0ZtUmFubURYajVCRzZsYzlvMWNsVEM3VXZSUW1OSUw5T2RERFo4cWxxWTJGaTBlenRCbnVvMkRVUzV0R2RWeThTZ3FQTTNFMTJmdGs0RWRsS3lyV21CcUZjWXdHeDRBY1NKODhPM3JRbVJCTXh0azByNXZoZ3I2aERDR3E3RkhLXC9oUUZQOUxoVU85MXF4V0V0TW43NlNhN0RQQ0xhcyt0Zk5SVndHMTJGQnVFWkZoZFNcL3FLTWRJWVVFNVE2dXdHVEV2VHpnMmttZ0pUM3NOYTZkYmhsWW5ZbjlpSWpUaDBkUEdnaVhhcDFCaGk4QjlhYVBGY0hFSFNxVzhuWlVJTmNyd2Y1QVVpKzdEK3FcL0FHNUl0aUJ0UVRDYWFGbTc0Z3Y1MXl1dHp3Z0tuSDlRK3gzbXR1S1wvdXdsTENzbGo5RGVYZ096TVdGeEZndXV3TEdYMzlrdERuZXR4TnczUExhYmpIa0RsR0RJZngwTUNRYWtNNzRzVGN1VzhJQ2lIdk5BN2Z4WENuYnRqc3k3YXRcL3lYWXdBZCtJRFM1MU1BXC9nM09ZVk40TSswcEc4NDNSZTZaNTNvT0RwMFltdWd4MEZOTzFOeFQzSE8xaGQ3ZFh5akFWXC90TlwvR0djQ0F3RUFBYU5GTUVNd0RnWURWUjBQQVFIXC9CQVFEQWdHR01CSUdBMVVkRXdFQlwvd1FJTUFZQkFmOENBUUV3SFFZRFZSME9CQllFRk5TbFVhcVMyaEdMRk1UXC9FWHJoSGVFeCtVcXhNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUJMcUlZb3JydFZ6NTZGNldPb0xYOUNjUmpTRmltN2dPODczYTNwNys2Mkk2am9YTXNNcjBuZDluUlBjRXdkdUVsb1pYd0ZnRXJWVVFXYVVaV05wdWUwbUd2VTdCVUFnVjlUdTBKMHlBKzlzcml6Vm9NdngrbzR6VEozVnU1cDVhVGYxYVlvSDF4WVZvNW9vRmdsXC9oSVwvRVhEMmxvXC94T1VmUEtYQlk3dHdmaXFPemlRbVRHQnVxUFJxOGgzZFFSbFhZeFhcL3J6R2Y4MFNlY0lUNndvOUthdkRrak9tSldHenpIc242UnlvNk1FQ2xNYVBuMHRlODd1a05ONzQwQWRQaFR2TmVaZFdsd3lxV0FKcHN2MjRjYUVja2pTcGdwb0laT2pjN1BBY0VWUU9XRlN4VWVzTWs0Sno1YlZaYVwvQUJqemNwK3JzcTFRTFNKNXF1cUh3V0ZUZXdDaHdwdzVncHcrRTVTcEtZNkZJSFBsVGRsK3FIVGh2Tjhsc0tOQVFnMHFUZEViSUZaQ1VRQzBDbDNUaTNxXC9jWHY4dGd1TEpOV3ZkR3pCNjAwWTMyUUhjbE1wZXlhYlQ0XC9RZU9lc3FweDZEYTcwSjJLdkxUMWo2Q2gyQnNLU3plVkxhaHJqbm9QcmRnaUlZWUJPZ2VBM1Q4U0UxcGdhZ3Q1NlI3bklrUlFidGVzb1JLaStOZkM3cFBiXC9HMVZVc2pcL2NSRUFISDFpMVVLYTBhQ3NJaUFOZkVkUU41T2s2d3RGSkpocDNhcEF2blZrclpEZk9HNXdlOWJZenZHb0k3U1VubGVVUkJKK04zaWhqQVJmTDRoRGVlUkhoWXlMa00za0V5RWtySkJMNXIwR0RqaWN4TSthRmNSMmZDQkFrdjNnclQ1a3o0a0xjdnNtSFgrOURCdz09Il0sImFsZyI6IlBTMjU2In0.eyJhY3NVUkwiOiJodHRwczovL3NlY3VyZTUuYXJjb3QuY29tL2Fjcy9hcGkvdGRzMi90eG4vYXBwL3YxL2NyZXEiLCJhY3NFcGhlbVB1YktleSI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IlEtRTY0WFg0Mjhxcl9fRWVJNVFlZTFPUHR3T3pxTWlhOXpCMEhEZ0xSSzgiLCJ5IjoidHpRVENYa0tmbHRUeklNX3h6REc2Y1BKSmFFYmxUMFhwMWU2Vl9DS2Z5TSJ9LCJzZGtFcGhlbVB1YktleSI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6Ind2OHd3SVA5Znd3OHNmVzdEeU5PbkxDekkyWWpRTjE2VzdLRWN5a21WcmsiLCJ5IjoiUmJwNW9YWHB3eVViS3gwZW1pYzc5VUpHQ05naUZCbF9CLW5NeDh3VVBsQSJ9fQ.uDNp5rdhxwY_ite8bJHEN9w02VDoWWqIhR0AyRSJbn_2wzCdPs1jJmg7st77Or4J7VO_Sz2ymjEkvUTUYR_EzCUYmUe3nRgb7HVtfF68s_aOMWQ0oU3G7tmDMmmUNWvARG9nohIT5z1BKYaxHIm_u3pRflQ5bepBNzPoEQ17atDwXr7uC-5vYrUTUuLQDcyl-Rd7pOsV3mZcv3UeiXWYxIsdmWlavQtP_gblcjlaeCYZ7CjFn9ndbfX2U19LZ75rDthdjEgp5fsCffiVxur2RWCbE2RRmqcsRXXajZowlGljiBLV1RhU-pg5zbxMgDHS9LnoZkkyfpR7tYbAQtppvQ"

        private val MASTERCARD_ROOT_CERT_CONTENTS = Base64(
            """
            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
            """.trimIndent()
        )

        private val MASTERCARD_ROOT_CERT = X509CertUtils.parse(
            MASTERCARD_ROOT_CERT_CONTENTS.decode()
        )

        private val MASTERCARD_ROOT_CERTS = listOf(MASTERCARD_ROOT_CERT)

        private val DISCOVER_CERT_CHAIN = listOf(
            Base64(
                """
                MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh
                MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
                d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
                QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT
                MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg
                U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
                ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83
                nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd
                KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f
                /ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX
                kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0
                /RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C
                AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY
                aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6
                Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1
                oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD
                QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v
                d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh
                xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB
                CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl
                5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA
                8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC
                2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit
                c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0
                j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz
                """.trimIndent()
            ),
            Base64(
                """
                MIIEkzCCA3ugAwIBAgICAV8wDQYJKoZIhvcNAQELBQAwgZwxCzAJBgNVBAYTAlVT
                MREwDwYDVQQIEwhJbGxpbm9pczETMBEGA1UEBxMKUml2ZXJ3b29kczEkMCIGA1UE
                ChMbRGlzY292ZXIgRmluYW5jaWFsIFNlcnZpY2VzMRkwFwYDVQQLExBQYXltZW50
                IFNlcnZpY2VzMSQwIgYDVQQDExtleHRlbmRlZHJvb3QucHJvdGVjdGJ1eS5jb20w
                HhcNMTcwMjAzMDAwMDAwWhcNMjcwMjAzMDAwMDAwWjCBpDELMAkGA1UEBhMCVVMx
                ETAPBgNVBAgTCElsbGlub2lzMRMwEQYDVQQHEwpSaXZlcndvb2RzMSQwIgYDVQQK
                ExtEaXNjb3ZlciBGaW5hbmNpYWwgU2VydmljZXMxGTAXBgNVBAsTEFBheW1lbnQg
                U2VydmljZXMxLDAqBgNVBAMTI2V4dGVuZGVkaW50ZXJtZWRpYXRlLnByb3RlY3Ri
                dXkuY29tMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA3Hb4PGfHF5qc
                1cX7EXsEdZyBeT8CXS879LlSFFsdxpTY3mbKBZXQKuZRwx4RAbwG4SROkgznhofp
                ta5AC4px/btVl0Q48sgs8+5HCRShohBOvW0c8bmSh37MwRq0B1FM+MyC7am0ijVO
                /PYn/+K9W64jS3KB0o5RffXEXxUv4SEF5hp5APLtpa5/KV7DL9kXj6znoZdXFTd2
                amjp77rG+jRG4pSKM9CLPiSur1oiJd5lBtimiwSqqbY7c/oRFXjPpigurrpfw3gy
                UcLhyFTzjRHjsDVhYpml6VKlUbvEuFhskkDFilx4Ss5ja4G2aFua/bFcX2FoM8TR
                ZJWKHz+fXwIBA6OB1jCB0zAfBgNVHSMEGDAWgBQo9O54ohDA+iqJRT8lpzFNgNwe
                0DAdBgNVHQ4EFgQU4T5ZrR/41KsRn2RnOQ9AdhlcuVkwEgYDVR0TAQH/BAgwBgEB
                /wIBADAPBgNVHQ8BAf8EBQMDAIQAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
                BQcDAjBNBgNVHR8ERjBEMEKiQIY+aHR0cDovL3d3dy5kaXNjb3ZlcmZpbmFuY2lh
                bGNlcnQuY29tL2NybHMvUmV2b2NhdGlvbkxpc3RfMy5jcmwwDQYJKoZIhvcNAQEL
                BQADggEBAJMrE5bT8qMHVXsVhB9W2tZGlqUBrH2NHy+Y1jxlVQRvDbaXqBV///Rs
                64ufL0yY9Nb24RjzdYwF3pylDqQR0ltZPu/o69OEUMVjM5PEs1fN3WZXSLp4ltw6
                NsnUvJSGyGQOQIESKFCdhYALvqzyuGACtpvSzGYSSk+Z45J9lxvXa8mf+vhNDHdg
                PfpSDyqSHqpl07YS/3dpNO1w7ft6PGmLeCk0049dO0oV1OJ23tcx0vIayD96T78M
                QL03lFPkjnusdJ7UxS7QfNbNKKzYS+P7+sExTHWrybJKzrlWz3DGxHRnY37QZ3/X
                nwxbgDe7y+r2l5x2n8fKhregYJThYew=
                """.trimIndent()
            ),
            Base64(
                """
                MIIElTCCA32gAwIBAgICAVwwDQYJKoZIhvcNAQELBQAwgZwxCzAJBgNVBAYTAlVT
                MREwDwYDVQQIEwhJbGxpbm9pczETMBEGA1UEBxMKUml2ZXJ3b29kczEkMCIGA1UE
                ChMbRGlzY292ZXIgRmluYW5jaWFsIFNlcnZpY2VzMRkwFwYDVQQLExBQYXltZW50
                IFNlcnZpY2VzMSQwIgYDVQQDExtleHRlbmRlZHJvb3QucHJvdGVjdGJ1eS5jb20w
                HhcNMTcwMjAzMDAwMDAwWhcNMjcwMjAzMDAwMDAwWjCBnDELMAkGA1UEBhMCVVMx
                ETAPBgNVBAgTCElsbGlub2lzMRMwEQYDVQQHEwpSaXZlcndvb2RzMSQwIgYDVQQK
                ExtEaXNjb3ZlciBGaW5hbmNpYWwgU2VydmljZXMxGTAXBgNVBAsTEFBheW1lbnQg
                U2VydmljZXMxJDAiBgNVBAMTG2V4dGVuZGVkcm9vdC5wcm90ZWN0YnV5LmNvbTCC
                ASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAO1otxObcaAkdZF3ldFTVNKc
                cpGk+OB+VyaA4tBmSdgefj1ykeycHRli9yZnECRySctMZ8T13HFRGvGLehBxbtex
                fVP6HP7SvwJUNlw7l2Bxdn6BNhEatmrRvz1rSURwWtWkWcJKz6sK0zsZwepXucyg
                77EeWcRkmaCs8pbre/NcvkzWuhXzoFAD4r56y04OzpW1Epu01hQd7fIB6Ck/juYw
                MoNQXYTWWVhGidsRoVxSdyYTlhAurTSXSpRwsiWeNroS11paejH1Mh8uU1frlrfj
                RubVMFkdKMnPzkgeE/IvCP76fpxba4hIvT8D+NKOhuV1ZKCKn+hsqPcTyfznjo8C
                AQOjgeAwgd0wHwYDVR0jBBgwFoAUKPTueKIQwPoqiUU/JacxTYDcHtAwHQYDVR0O
                BBYEFCj07niiEMD6KolFPyWnMU2A3B7QMBIGA1UdEwEB/wQIMAYBAf8CAQEwDwYD
                VR0PAQH/BAUDAwCGADAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsG
                AQUFBwMJME0GA1UdHwRGMEQwQqJAhj5odHRwOi8vd3d3LmRpc2NvdmVyZmluYW5j
                aWFsY2VydC5jb20vY3Jscy9SZXZvY2F0aW9uTGlzdF8zLmNybDANBgkqhkiG9w0B
                AQsFAAOCAQEAX+U6rteEJU7XF+Ze6E9wVpkP59PUZHWE+ffe+qCBpBPrKv9/BZHI
                A17WLiNSIFpM/HwcCaLRymUzt8KR9LiriZ493xNB8ZF6MAs1zVUGWCT7frX/Y+Te
                asQq0l0DRCIZSQaCO5R7BuV8q95O0jP5EjuC5BPonJDY5ME3eYQR6MYrRSZ8DeoD
                fA8mVa5BjBIg1HRZZn6Ay+4hLdcfhBuUmDrjsnaCr/HJn8/tN4De2FYv7txOzg+t
                Jsw8Vo8oFcztrH4rmi8CSiZ8qhV1dIkDo7H+wo75/AkAF/FL6HhZHsS9VdMtbqIz
                m6C3zea/yyGQ78n2SY6sNbTOPh3lpKPrOg==
                """.trimIndent()
            )
        )

        private val DISCOVER_ROOT_CERT = X509CertUtils.parse(
            Base64(
                """
            MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
            MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
            d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
            QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
            MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
            b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
            9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
            CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
            nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
            43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
            T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
            gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
            BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
            TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
            DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
            hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
            06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
            PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
            YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
            CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
                """.trimIndent()
            ).decode()
        )
    }
}
